package com.hss01248.facedetect.activity;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.media.ExifInterface;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.faceplusplus.api.FaceDetecter;
import com.google.gson.Gson;
import com.hss01248.facedetect.BaseURL;
import com.hss01248.facedetect.CheckType;
import com.hss01248.facedetect.FaceCj;
import com.hss01248.facedetect.FaceTrackListener;
import com.hss01248.facedetect.MyApplication;
import com.hss01248.facedetect.MyBitmapUtils;
import com.hss01248.facedetect.MyImageFileUtils;
import com.hss01248.facedetect.R;
import com.hss01248.facedetect.constant.Global;
import com.hss01248.facedetect.response.CheckTicketResponse;
import com.hss01248.facedetect.response.FaceDataComparisonResponse;
import com.hss01248.facedetect.utils.Base64Utils;
import com.hss01248.facedetect.utils.MyProgressUtils;
import com.hss01248.facedetect.utils.MyProgressUtils_Face;
import com.hss01248.facedetect.utils.SHExtends;
import com.hss01248.facedetect.utils.SPUtils;
import com.hss01248.facedetect.utils.ToastUtil;
import com.hss01248.facedetect.utils.httpUtils;
import com.hss01248.facedetect.view.FaceMask;
import com.hss01248.facedetect.view.LoadingView;
import com.hss01248.titlebarlib.Titlebar;
import com.maning.mndialoglibrary.MProgressDialog;
import com.maning.mndialoglibrary.MToast;
import com.maning.mndialoglibrary.config.MDialogConfig;
import com.maning.mndialoglibrary.listeners.OnDialogDismissListener;

import org.json.JSONObject;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Locale;

public class FaceTrackActivity extends BaseActivity implements Callback, PreviewCallback, FaceTrackListener {


    private ImageView fa_img_result;

    /**********************语音合成**********************/
//语音引擎
    private class TTSListener implements TextToSpeech.OnInitListener {
        @Override
        public void onInit(int status) {
            // TODO Auto-generated method stub
            if (status == TextToSpeech.SUCCESS) {
                Log.i(TAG, "onInit: TTS引擎初始化成功");
            } else {
                Log.i(TAG, "onInit: TTS引擎初始化失败");
            }
        }
    }

    private static final String TAG = "PhoneActivity";
    private TextToSpeech mSpeech = null;
    private static float m_voice_speed = 1.2f;   //合成语音的语速
    private static float m_voice_pitch = 1.0f;   //合成语音的语调
    /****************************************************/


    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1) {


            }
        }
    };

    SurfaceView svPreview;
    FaceMask fmMask;

    private Camera mCamera;
    private HandlerThread handleThread;
    private Handler detectHandler;

    private int width = 640;
    private int height = 480;
    private FaceDetecter facedetecter;

    Activity activity;
    Titlebar titlebar;
    private TextView fa_tv_ticketNo;
    private TextView fa_tv_message;

    private SHExtends she;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_face_track);
        svPreview = (SurfaceView) findViewById(R.id.sv_preview_track);
        fmMask = (FaceMask) findViewById(R.id.fm_mask_track);
        titlebar = (Titlebar) findViewById(R.id.titlebar);

        titlebar.init(this);
        titlebar.setTitle("人脸检票");
        titlebar.getRootView().setBackgroundColor(Color.parseColor("#43aea8"));

        titlebar.getIvLeft().setVisibility(View.INVISIBLE);
        titlebar.getTvRight().setVisibility(View.INVISIBLE);

        activity = this;

        try {
            initData();
        } catch (Exception e) {
            Toast.makeText(this, "异常" + e.getMessage(), Toast.LENGTH_SHORT).show();
        }

        fa_tv_ticketNo = (TextView) findViewById(R.id.fa_tv_ticketNo);
        fa_tv_message = (TextView) findViewById(R.id.fa_tv_message);
        fa_img_result = (ImageView) findViewById(R.id.fa_img_result);

        mSpeech = new TextToSpeech(FaceTrackActivity.this, new TTSListener());
        initBote();
    }

    private void initBote() {
        try {
            she = new SHExtends("/dev/ttyS3", "9600");
            she.open();
        } catch (Exception e) {
            ToastUtil.showToast("灯带Com口异常：" + e.getMessage());
            e.printStackTrace();
        }
    }

    //播放合成语音
    public void PlayAudioFile(String str) {
        //设置中文
        int supported = mSpeech.setLanguage(Locale.CHINA);
        mSpeech.setSpeechRate(m_voice_speed);
        mSpeech.setPitch(m_voice_pitch);

        if ((supported != TextToSpeech.LANG_AVAILABLE) && (supported != TextToSpeech.LANG_COUNTRY_AVAILABLE)) {
            //语言设置失败
            Log.i(TAG, "中文设置失败");
        } else {
            Log.i(TAG, "中文设置成功");
        }
        //mSpeech.speak(str, TextToSpeech.QUEUE_FLUSH, null);
        mSpeech.speak(str, TextToSpeech.QUEUE_ADD, null);



    }


    private void initData() {
        handleThread = new HandlerThread("dt");
        handleThread.start();
        detectHandler = new Handler(handleThread.getLooper());
        svPreview.getHolder().addCallback(this);
        svPreview.setKeepScreenOn(true);

        facedetecter = new FaceDetecter();
        facedetecter.init(this, Global.FACEPP_KEY);
        facedetecter.setTrackingMode(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
//            特别注意，在手机上，前置是1，后置是0
//                    在工控机上，前置是0

            if (Camera.getNumberOfCameras() > 1) {
                mCamera = Camera.open(1);
            } else {
                mCamera = Camera.open(0);
            }
//            接口回调的。。。。。。，越调越多
            fmMask.setCamera(mCamera, fmMask, (FaceTrackActivity) activity, fa_tv_ticketNo, fa_tv_message, fa_img_result, mSpeech,she);

            if (null == mCamera) {
                Toast.makeText(this, "摄像头为空", Toast.LENGTH_SHORT).show();
                return;
            }
            mCamera.setDisplayOrientation(90);
            Camera.Parameters para = mCamera.getParameters();
                 /* List<Camera.Size> sizes =   para.getSupportedPreviewSizes();
        int count = sizes.size();
        for (int i = 0; i< count; i++){
            Camera.Size size = sizes.get(i);
            if (size.width > 800 && size.width < 1000){
                width = size.width;
                height = size.height;
                break;
            }
            Log.e("size","size w:"+size.width + "--h:"+size.height);

        }


*/
            Point showingArea = new Point();
            WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
            Display display = wm.getDefaultDisplay();
            int screenWidth = display.getWidth();
            int screenHeight = display.getHeight();

            int topHeight = dip2px(activity, 25 + 44);//状态栏+titlebar
            showingArea.set(screenWidth, screenHeight - topHeight);


            Point point = getBestCameraResolution(para, showingArea);

            width = point.x;
            height = point.y;
//            width = 352;
//            height = 288;
            width=640;
            height=480;
//            width=1280;
//            height=720;
            //todo 预览变形的问题
            Log.i("size", "size w:" + width + "--h:" + height);
        /*:1920--h:1080
09-19 15:30:11.068 19768-19768/com.hss01248.facedemo E/size: size w:1440--h:1080
09-19 15:30:11.068 19768-19768/com.hss01248.facedemo E/size: size w:1280--h:720
09-19 15:30:11.068 19768-19768/com.hss01248.facedemo E/size: size w:1056--h:864
09-19 15:30:11.068 19768-19768/com.hss01248.facedemo E/size: size w:960--h:720
09-19 15:30:11.068 19768-19768/com.hss01248.facedemo E/size: size w:720--h:480
09-19 15:30:11.068 19768-19768/com.hss01248.facedemo E/size: size w:640--h:480
09-19 15:30:11.068 19768-19768/com.hss01248.facedemo E/size: size w:352--h:288
09-19 15:30:11.068 19768-19768/com.hss01248.facedemo E/size: size w:320--h:240*/

            para.setPreviewSize(width, height);
            mCamera.setParameters(para);
        } catch (Exception e) {
            Toast.makeText(this, "异常" + e.getMessage(), Toast.LENGTH_SHORT).show();
        }

    }

    public static int dip2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    private Point getBestCameraResolution(Camera.Parameters parameters, Point screenResolution) {
        float tmp = 0f;
        float mindiff = 100f;
        float x_d_y = (float) screenResolution.x / (float) screenResolution.y;
        Camera.Size best = null;
        List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
        for (Camera.Size s : supportedPreviewSizes) {
            tmp = Math.abs(((float) s.height / (float) s.width) - x_d_y);
            if (tmp < mindiff) {
                mindiff = tmp;
                best = s;
            }
        }
        return new Point(best.width, best.height);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        try {
            if (mCamera == null) return;
            mCamera.setPreviewDisplay(holder);
            mCamera.setDisplayOrientation(90);
            mCamera.startPreview();
            mCamera.setPreviewCallback(this);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCamera == null) return;
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }

    @Override
    public void onPreviewFrame(final byte[] data, final Camera camera) {

        // 这个方法 让数据方向进行调整
//        final byte[] datas = rotateYUV420Degree180(data, width, height);

        camera.setPreviewCallback(null);
        if (mCamera == null) return;
        detectHandler.post(new Runnable() {
            @Override
            public void run() {
                int is = 0;
                final byte[] ori = new byte[width * height];

                for (int x = width - 1; x >= 0; x--) {
                    for (int y = height - 1; y >= 0; y--) {
                        ori[is++] = data[y * width + x];
                    }
                }


                final FaceDetecter.Face[] faceinfo = facedetecter.findFaces(ori, height, width);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        fmMask.setFaceInfo(faceinfo);
                    }
                });


                try {
                    camera.setPreviewCallback(FaceTrackActivity.this);
                } catch (Exception e) {
                    e.printStackTrace();
                }


            }
        });
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        facedetecter.release(this);
        handleThread.quit();
        detectHandler = null;
        if (mSpeech != null) {
            mSpeech.shutdown();
        }
        if (she!=null) {
            she.lightOff();
            she.close();
        }
    }

    /**
     * 获取图片的旋转角度
     *
     * @param path
     * @return int
     * @Title: readPictureDegree
     * @date 2012-12-4 上午9:22:33
     */
    private int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);

            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
                default:
                    degree = 0;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    @Override
    public void PassCamera(Camera camera, FaceMask faceMask, Activity activity, TextView tv_ticketNo, TextView tv_message, ImageView img_result, TextToSpeech mSpeech,SHExtends fm_she) {
        //借用接口回调，返回camera对象和facemask对象
        takePic(camera, faceMask, activity, tv_ticketNo, tv_message, img_result, mSpeech,fm_she);
    }

    private void takePic(Camera camera, FaceMask faceMask, Activity factivity, TextView tv_ticketNo, TextView tv_message, ImageView img_result, TextToSpeech fmSpeech,SHExtends fm_she) {


        fmMask = faceMask;
        activity = factivity;
        fa_tv_ticketNo = tv_ticketNo;
        fa_tv_message = tv_message;
        fa_img_result = img_result;
        mSpeech = fmSpeech;
        she=fm_she;

        if (camera != null) {
            Camera.Parameters param = camera.getParameters();
            param.setPictureSize(640, 480);//如果不设置会按照系统默认配置最低160x120分辨率，对应参数是对的

            camera.setParameters(param);

            camera.takePicture(null, null, null, new Camera.PictureCallback() {
                @Override
                public void onPictureTaken(byte[] data, Camera camera) {

                    //也会影响拍摄分辨率
//                    720*960

                    Bitmap bitmap = MyBitmapUtils.byteToBitmap(data, 640, 720);

                    //然后将bitmap旋转270度
                    final Bitmap bitmap1 = MyBitmapUtils.rotateBitmap(bitmap, 270, true);
                    bitmap.recycle();


                    File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
                    final File file = new File(dir, "capture" + ".jpg");

                    if (!file.exists()) {
                        try {
                            file.createNewFile();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    FileOutputStream outSteam = null;
                    try {
                        outSteam = new FileOutputStream(file);
                        bitmap1.compress(Bitmap.CompressFormat.JPEG, 100, outSteam);
                        bitmap1.recycle();
                        //int degree = readPictureDegree(file.getAbsolutePath());
                        // setPictureDegreeZero(file.getAbsolutePath());
//                      截取bitmap
                        final Bitmap bitmap_collect = FaceCj.cutFace(BitmapFactory.decodeFile(file.getAbsolutePath()), FaceTrackActivity.this);
//                       保存bitmap
                        MyBitmapUtils.saveBitmap(bitmap_collect, file.getAbsoluteFile());

                        fa_img_result.post(new Runnable() {
                            @Override
                            public void run() {
                                fa_img_result.setImageBitmap(bitmap_collect);
                            }
                        });

//                        人脸1：n检票
                        faceDataComparison(Base64Utils.imageToBase64Str(file.getAbsolutePath()), String.valueOf(SPUtils.get(activity,"CHECK_TICKET_TERMINAL_N0","")), activity);


                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {

                        if (outSteam != null) {
                            try {
                                outSteam.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }

                    }
                    camera.startPreview();  //如果不调用 ，则画面不会更新

                }
            });


        }
    }


    void faceDataComparison(final String imgTobase64String, final String gateNo, final Activity activity) {

//        MProgressDialog.showProgress(activity,"加载中...");
//        没有封装的progressDialog，意外情况下无法关闭弹窗，自定义，能够手动取消
        MyProgressUtils_Face.showProgressDialog(activity);

        new Thread(new Runnable() {
            @Override
            public void run() {

                // 先封装一个 JSON 对象
                JSONObject param = new JSONObject();

                try {

                    param.put("imgBaseData", imgTobase64String);
                    param.put("gateNo", gateNo);


                    param.put("sign", "A96D48AE69F46BD0E1B17F10316086F3");
                    param.put("timestamp", "20180611165000");


                    String ss = httpUtils.postJson(String.valueOf(SPUtils.get(activity,"url","")) + BaseURL.URL_faceDataComparison, param);
                    FaceDataComparisonResponse response = new Gson().fromJson(ss, FaceDataComparisonResponse.class);
                    if (response.getCode().equals("0")) {

                        checkTicketAgain(CheckType.TYPE_FACE, response.getData(), String.valueOf(SPUtils.get(activity,"CHECK_TICKET_TERMINAL_N0","")));

                    } else {
//                        这里要写到子线程吐司上面，放到吐司下面，语句不执行，就没法继续检票了

                        sleep2000();
//                        取消弹窗
                        MyProgressUtils_Face.dismissProgress();
                        she.lightRed();

                        PlayAudioFile("人脸比对失败");
                        fa_img_result.post(new Runnable() {
                            @Override
                            public void run() {
                                fa_img_result.setImageResource(R.drawable.img_result_fail);
                            }
                        });

//                        ToastUtil.showToast("faceDataComparison失败：" + response.getMessage());
                    }

                } catch (Exception e) {
                    she.lightRed();
                    sleep2000();
                    MyProgressUtils_Face.dismissProgress();
                    ToastUtil.showToast("faceDataComparison异常：" + e.getMessage());
                } finally {

                    clearTextAfterCheck();

                }
            }
        }).start();
    }

    void checkTicketAgain(final String checkType, final String typeData, final String gateNo) {
        new Thread(new Runnable() {
            @Override
            public void run() {

                // 先封装一个 JSON 对象
                JSONObject param = new JSONObject();

                try {

                    param.put("searchDataType", checkType);
                    param.put("searchData", typeData);
                    param.put("checkCount", -1);
                    param.put("gateNo", gateNo);
                    param.put("isCollectionGate", "Y");

                    param.put("sign", "A96D48AE69F46BD0E1B17F10316086F3");
                    param.put("timestamp", "20180611165000");


                    String ss = httpUtils.postJson(String.valueOf(SPUtils.get(activity,"url","")) + BaseURL.URL_checkTicket, param);
                    final CheckTicketResponse response = new Gson().fromJson(ss, CheckTicketResponse.class);
                    int result = Integer.valueOf(response.getCode());


//                    取消弹窗
                    MProgressDialog.dismissProgress();
                    switch (result) {
                        case 0:
                            she.lightGreen();
                            if (response.getData().getBarcodeNo() != null) {
                                showMessage(response);
                            }
                            if (response.getData().getGateSoundName() != null) {

                                PlayAudioFile(response.getData().getGateSoundName());
                            }
//                            sleep2000();
                            break;

                        default:
                            if (response.getData().getBarcodeNo() != null) {

                            }

                            showMessage(response);
                            she.lightRed();
                            PlayAudioFile(response.getMessage());
//                            sleep2000();
//                            ToastUtil.showToast("checkTicketAgain失败：" + response.getMessage());
                            break;

                    }

                } catch (Exception e) {
                    she.lightRed();
                    MyProgressUtils_Face.dismissProgress();
                    ToastUtil.showToast("checkTicketAgain异常：" + e.getMessage());
                } finally {
                    //清除记录
                    clearTextAfterCheck();
                    sleep2000();
                }

            }
        }).start();
    }

    private void clearTextAfterCheck() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                clearText();
            }
        }).start();
    }

    void showMessage(final CheckTicketResponse response) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                fa_tv_ticketNo.setText(response.getData().getBarcodeNo());

                fa_tv_message.setText(response.getMessage());
                if (response.getCode().equals("0")) {
                    fa_img_result.setImageResource(R.drawable.img_result_success);

                } else {
                    fa_img_result.setImageResource(R.drawable.img_result_fail);

                }

            }
        });
    }

    void clearText() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {

                fa_tv_ticketNo.setText("");
                fa_tv_message.setText("");
//                fa_img_result.setBackgroundDrawable(getResources().getDrawable(R.drawable.img_result_normal));
//                fa_img_result.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher));
                fa_img_result.setImageResource(R.drawable.img_result_normal3);
            }
        });
    }

    void sleep2000() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        runOnUiThread(new Runnable() {
            @Override
            public void run() {

                if (fmMask != null) {
                    fmMask.setShoot();
                }

            }
        });

    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        MyProgressUtils_Face.dismissProgress();
    }

    protected void hideBottomUIMenu() {
        //隐藏虚拟按键，并且全屏
        if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
            View v = this.getWindow().getDecorView();
            v.setSystemUiVisibility(View.GONE);
        } else if (Build.VERSION.SDK_INT >= 19) {
            //for new api versions.
            View decorView = getWindow().getDecorView();
            int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
            decorView.setSystemUiVisibility(uiOptions);
        }
    }

    private byte[] rotateYUV420Degree180(byte[] data, int imageWidth, int imageHeight) {
        byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];
        int i = 0;
        int count = 0;
        for (i = imageWidth * imageHeight - 1; i >= 0; i--) {
            yuv[count] = data[i];
            count++;
        }
        i = imageWidth * imageHeight * 3 / 2 - 1;
        for (i = imageWidth * imageHeight * 3 / 2 - 1; i >= imageWidth
                * imageHeight; i -= 2) {
            yuv[count++] = data[i - 1];
            yuv[count++] = data[i];
        }
        return yuv;
    }

}
